package com.fanshuai.soring.boot.mvc.metrics;

import io.prometheus.client.Counter;
import io.prometheus.client.Summary;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

public class MetricsFilter extends OncePerRequestFilter  {
    Summary httpLatency = Summary.build()
            .name("http_latency")
            .help("http_latency")
            .quantile(0.5d, 0.1)
            .quantile(0.75d, 0.05)
            .quantile(0.95d, 0.03)
            .quantile(0.98d, 0.01)
            .labelNames("uri", "ip")
            .register();

    Counter successCount = Counter.build()
            .name("success_count")
            .help("success_count")
            .labelNames("uri")
            .register();

    Counter errCount = Counter.build()
            .name("error_count")
            .help("error_count")
            .labelNames("uri")
            .register();

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        long start = System.currentTimeMillis();
        String uri = httpServletRequest.getRequestURI();

        try {
            filterChain.doFilter(httpServletRequest, httpServletResponse);

            successCount.labels(uri).inc();
            successCount.labels("all").inc();
        } catch (Exception e) {
            errCount.labels(uri).inc();
            errCount.labels("all").inc();
            throw e;
        } finally {
            long time = System.currentTimeMillis() - start;
            httpLatency.labels(uri, getLocalIP()).observe(time);
            httpLatency.labels("all", getLocalIP()).observe(time);
        }
    }

    public String getLocalIP() {
        try {
            InetAddress address = InetAddress.getLocalHost();
            return address.getHostAddress();
        } catch (Exception e) {
            return "";
        }
    }

    public List<String> getAllLocalIPs() throws SocketException {
        List<String> ips = new ArrayList<>();

        Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
        while (networkInterfaces.hasMoreElements()) {
            NetworkInterface networkInterface = networkInterfaces.nextElement();
            Enumeration<InetAddress> addresses = networkInterface.getInetAddresses();
            while (addresses.hasMoreElements()) {
                InetAddress address = addresses.nextElement();
                if (!(address instanceof Inet6Address) && !address.isLoopbackAddress()) {
                    ips.add(address.getHostAddress());
                }
            }
        }

        return ips;
    }
}
